package com.shou.interceptor;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shou.api.model.response.ResultData;
import com.shou.types.common.Constants;
import com.shou.types.common.rediskey.TokenContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.io.PrintWriter;

@Component
@Order(1)
public class AuthenticationInterceptor implements HandlerInterceptor {

    private static final Logger SECURITY_LOGGER = LogManager.getLogger(Constants.Logger.SECURITY_LOGGER);
    @Value("${sa-token.timeout:86400}")
    private long tokenTimeout;
    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws IOException {
        SECURITY_LOGGER.info("AuthenticationInterceptor: preHandle");
        try {
            if (!checkIsControllerMethod(handler)||checkIsInternalRequest(request)||checkTokenIsValid()) {
                return true;
            }
        }catch (NotLoginException e){
            SECURITY_LOGGER.error("TokenUserInterceptor:preHandle:{}", e.getMessage(), e);
            setErrorResponse(response,e);
            return false;
        }
        return true;
    }

    private boolean checkIsControllerMethod(Object handler){
        return handler instanceof HandlerMethod;
    }

    private boolean checkIsInternalRequest(HttpServletRequest request){
        String internalRequestHeader = request.getHeader("Internal-Request");
        // 内部请求，直接放行
        return "true".equals(internalRequestHeader);
    }

    private boolean checkTokenIsValid(){
        long userId = StpUtil.getLoginIdAsLong();
        TokenContext.setBaseUserInfo(TokenContext.BaseUserInfo.builder()
                        .userId(userId)
                        .userName(String.valueOf(StpUtil.getSession().get("userName")))
                        .build());
        //续约长期有效期，避免redis中大量无效的token
        StpUtil.renewTimeout(tokenTimeout);
        System.out.println("checkTokenIsValid: userId: " + userId);
        return true;
    }

    private void setErrorResponse(HttpServletResponse response, NotLoginException e) throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);

        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(ResultData.fail(String.valueOf(e.getCode()), e.getMessage()));
        PrintWriter printWriter = response.getWriter();
        printWriter.print(json);
        printWriter.flush();
        printWriter.close();
    }
}
